//
// Created by DELL on 2023/4/27.
//

#include <iostream>
#include <memory>

class Base
{
public:
    Base()
    {
        std::cout << "Base Construct.  \n";
    }

    virtual ~Base()
    {
        std::cout << "Base Destruct.  \n";
    }

    virtual void fun()
    {
        std::cout << "Base::fun" << std::endl;
    }

    int n{0};
};

class Base2
{
public:
    int n1{1};
    int n2{2};
};

class Derive : public Base, public Base2, public std::enable_shared_from_this<Derive>
{
public:
    Derive()
    {
        std::cout << "Derive Construct.  \n";
    }

    ~Derive() override
    {
        std::cout << "Derive Destruct.  \n";
    }


    void fun() override
    {
        std::cout << "Derive::fun" << std::endl;
    }
};

int main()
{
    // shared_ptr
    {
        std::cout << "------------- shared_ptr -----------------" << std::endl;
        std::shared_ptr<Derive> spDriver = std::make_shared<Derive>();
        auto spB1 = std::dynamic_pointer_cast<Base, Derive>(spDriver);
        auto spB2 = std::dynamic_pointer_cast<Base2, Derive>(spDriver);
        auto spInt = std::shared_ptr<int>(spDriver, &spB2->n2);
        std::cout << "spB1: " << spB1  << std::endl;
        std::cout << "spB2: " << spB2  << std::endl;
        std::cout << "spInt: " << spInt  << std::endl;
    }

    {
        std::cout << "------------- make_shared destruct -----------------" << std::endl;
        std::weak_ptr<Base> weakPtr;
        {
            auto spPtr = std::make_shared<Base>();
            weakPtr = spPtr;
        }
        std::cout << "weakPtr expired:" << weakPtr.expired() << std::endl;
    }

    {
        std::cout << "------------- unique_ptr -----------------" << std::endl;
        auto deleter = [](Base* p) { delete p; };
        using DeleterType = decltype(deleter);
        std::unique_ptr<Derive, DeleterType> up = std::unique_ptr<Derive, DeleterType>(new Derive, deleter);
        std::unique_ptr<Base, DeleterType> up2 = std::move(up);
        std::unique_ptr<Derive> up3 = std::unique_ptr<Derive>(dynamic_cast<Derive*>(up2.release()));
    }

    {
        std::cout << "----------weak_ptr-----------" << std::endl;
        std::weak_ptr<Base> wp;
//        std::shared_ptr<Base> sp(wp); // wp为null会崩溃
        auto sp = wp.lock(); // sp == nullptr
    }

    {
        std::cout << "----------enable_shared_from_this-----------" << std::endl;
        struct A : public std::enable_shared_from_this<A>
        {
            A()
            {
                // 运行时会崩溃 因为enable_shared_from_this内部的weak_ptr为nullptr导致shared_ptr构造抛出异常
//                std::cout << "Construct shared_from_this is null: " << (shared_from_this() != nullptr) << std::endl;
                // 可以使用weak_from_this
                std::cout << "A Construct weak_from_this not null: " << (weak_from_this().lock() != nullptr) << std::endl;
            }
            void f() { std::cout << "A shared_from_this not null: " << (shared_from_this() != nullptr) << std::endl;  }
        };
        auto a = std::shared_ptr<A>(new A);
        a->f();

        struct B : private std::enable_shared_from_this<B>
        {
            void f()
            {
                // private 继承会导致构造shared_ptr无法识别到enable_shared_from_this类型，从而不能这种内部的weak_ptr，导致调用shared_from_this崩溃
//                std::cout << "B shared_from_this is null: " << (shared_from_this() != nullptr) << std::endl;
                std::cout << "B weak_from_this not  null: " << (weak_from_this().lock() != nullptr) << std::endl;
            }
        };
        auto b = std::make_shared<B>();
        b->f();

        struct C : public  A, public std::enable_shared_from_this<C>
        {};
        std::cout << "sizeof(A):" << sizeof(A) << ", sizeof(C): "<< sizeof (C) << std::endl;

    }
    {
        std::cout << "------------- enable_shared_from_this 2 -----------------" << std::endl;
        struct A : public std::enable_shared_from_this<A>
        {
            virtual ~A() = default;
            std::weak_ptr<A> wpA() { return weak_from_this(); }
            std::shared_ptr<A> spA() { return shared_from_this(); }
        };
        struct B : public std::enable_shared_from_this<B>, public A
        {
            std::weak_ptr<B> wpB() { return std::enable_shared_from_this<B>::weak_from_this();}
            std::shared_ptr<B> spB() { return std::enable_shared_from_this<B>::shared_from_this();}
        };
        struct C : public A
        {
            std::weak_ptr<C> wpC() { return  std::dynamic_pointer_cast<C>(weak_from_this().lock());}
            std::shared_ptr<C> spC() { return std::dynamic_pointer_cast<C>(shared_from_this());}
        };

        std::shared_ptr<B> spB = std::shared_ptr<B>(new B);
        std::cout << "B, wpB weak_from_this expired: " << spB->wpB().expired() << std::endl;
        std::cout << "B, wpA weak_from_this expired: " << spB->wpA().expired() << std::endl;

        std::shared_ptr<C> spC = std::shared_ptr<C>(new C);
        std::cout << "C, wpC weak_from_this expired: " << spC->wpC().expired() << std::endl;
        std::cout << "C, wpA weak_from_this expired: " << spC->wpA().expired() << std::endl;
    }

    {
        std::cout << "----------Array-----------" << std::endl;

        {
            std::cout << "----------unique_ptr array-----------" << std::endl;
            std::unique_ptr<Base[]> upBaseArray = std::unique_ptr<Base[]>(new Base[2]);
            upBaseArray[0].n;
        }

        {
            std::cout << "----------C++17 shared_ptr array-----------" << std::endl;
            std::shared_ptr<Base[]> spBaseArray = std::shared_ptr<Base[]>(new Base[2]);
            spBaseArray[0].n;
        }

    }

    return 0;
}